<template>
  <el-card class="">
    <div class="hex-editor">
      <div class="hexrow header">
        <span class="addr"></span>
        <span class="hex">
          <span class="hex-cell" v-for="(item, index) in hexAscii" :key="index">{{ item }}</span>
        </span>
        <span class="ascii">
          <span class="ascii-cell" v-for="(item, index) in hexAscii" :key="index">{{ item }}</span>
        </span>
      </div>
      <!-- <view class="scroller-container"> -->
          <!-- <recycle-scroller ref="scroller" class="scroller hexrow" :items="splitedContent" v-slot="{ item, index, active }" key-field="id" :item-size="20" :buffer="10000" @visible="onScrollerActive">  -->
        <div class="hexrow" v-for="(item, index) in splitedContent">
          <view>
            <!-- <span class="addr">{{ item.id }}</span> -->
            <span class="addr">{{ byteToHex(index * 16, 8) }}</span>
            <span class="hex">
              <span :class="['hex-cell', { selected: isSelected(index, col) }]" @mousedown="hexCellMouseDown(index, col)"
                @mouseover="hexCellMouseOver(index, col)" @mouseup="hexCellMouseUp(index, col)"
                @click="hexCellClicked(index, col)" v-for="(cell, col) in item.arr" :key="col">{{ byteToHex(cell) }}</span>
              <span class="hex-cell" v-if="item.arr.length < 16" v-for="col in (16 - item.arr.length)" :key="col">&nbsp</span>
            </span>
            <span class="ascii">
              <span :class="['ascii-cell', { selected: isSelected(index, col) }]" @mousedown="hexCellMouseDown(index, col)"
                @mouseover="hexCellMouseOver(index, col)" @mouseup="hexCellMouseUp(index, col)"
                @click="hexCellClicked(index, col)" v-for="(cell, col) in item.arr" :key="col">{{ byteToChar(cell) }}</span>
            </span>
          </view>
        </div>
        <!-- </recycle-scroller>   -->
      <!-- </view> -->
    </div>
  </el-card>
  <el-card class="mt-2">
    <el-descriptions :column="2" size="small" border> 
      <el-descriptions-item label="选中范围">0x{{ byteToHex(startIndex || 0, 8) }} - 0x{{ byteToHex(endIndex || 0, 8) || 0 }}</el-descriptions-item> 
      <el-descriptions-item label="选中数量">{{ endIndex - startIndex + 1 || 0 }} (0x{{ byteToHex(endIndex - startIndex + 1 || 0) }})</el-descriptions-item> 
    </el-descriptions>
  </el-card>
</template>

<script>
import { RecycleScroller } from 'vue-virtual-scroller'  
export default {
  components: {  
    RecycleScroller  
  },  
  props: {
    content: Uint8Array,
  },
  watch: {
    content(newValue, oldValue) {
      this.splitedContent = this.splitByteArray(newValue);
      // this.splitedContent = [];
      // let timer = setInterval(() => {
      //   if (this.scrollerActive) {
      //     this.splitedContent = this.splitByteArray(newValue);
      //     console.log("this.splitedContent", this.splitedContent);
      //     this.$refs.scroller.scrollToPosition(0);
      //     clearInterval(timer);
      //   } 
      // }, 100);
    }
  },
  data() {
    return {
      hexAscii: "0123456789ABCDEF",
      startIndex: -1,
      endIndex: -1,
      originMovingIndex: -1,
      details: [
        { label: `选中字节数：${this.endIndex - this.startIndex + 1 || 0}`},
      ],
      splitedContent: [],
      scrollerActive: true,
    };
  },
  mounted() {
    // this.splitedContent = this.splitByteArray(this.content);
    document.addEventListener('mouseup', this.hexCellMouseUp);
  },
  methods: {
    onScrollerActive() {
      this.scrollerActive = true;
    },
    updateSelectedInde(startIndex, endIndex) {
      this.startIndex = startIndex;
      this.endIndex = endIndex;
    },
    splitByteArray(content) {
      if (!content) {
        return [];
      }
      let result = [];
      for (let i = 0; i < content.length; i += 16) {
        let chunk = content.slice(i, i + 16);
        result.push({
          id: `${this.guid()}.${i}`,
          arr: chunk,
        });
      }
      return result;
    },
    byteToHex(byte, size = 2) {
      return byte.toString(16).padStart(size, '0');
    },
    byteToChar(byte) {
      // let byte = char.charCodeAt(0);
      if (byte == 32) {
        return '\u00a0';
      }
      if (byte < 32 || (byte <= 0xa0 && byte >= 0x7f) || byte == 0xad) {
        return ".";
      }
      return String.fromCharCode(byte)
    },
    hexCellClicked(row, index) {
      index = row * 16 + index;
      this.startIndex = index;
      this.endIndex = index;
    },
    hexCellMouseDown(row, index) {
      this.originMovingIndex = row * 16 + index;
      this.hexCellClicked(row, index);
    },
    hexCellMouseOver(row, index) {
      if (this.originMovingIndex != -1) {
        let globalIndex = row * 16 + index;
        if (globalIndex > this.originMovingIndex) {
          this.startIndex = this.originMovingIndex;
          this.endIndex = globalIndex;
        }
        if (globalIndex < this.originMovingIndex) {
          this.startIndex = globalIndex;
          this.endIndex = this.originMovingIndex;
        }
      }
    },
    hexCellMouseUp(row, index) {
      this.originMovingIndex = -1;
    },    
    isSelected(row, index) {
      if (this.startIndex === -1 || this.endIndex === -1) {
        return false;
      }
      index = row * 16 + index;
      return index >= this.startIndex && index <= this.endIndex;
    },
    guid() {
      return 'xxxxxxxx'.replace(/[xy]/g, function (c) {
          var r = Math.random() * 16 | 0,
              v = c == 'x' ? r : (r & 0x3 | 0x8);
          return v.toString(16);
      });
    }
  },
  computed: {
    
  }
};
</script>

<style scoped lang="scss">
.hex-editor {
  box-sizing: content-box;
  min-width: 600px;
  font-size: 12px;

  span {
    display: inline-block;
    text-align: center;
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+/Edge */
    user-select: none; /* Standard syntax */
  }

  .header {
    // background: #eee;
    color: #ccc;
  }

  .hexrow {
    text-align: left;

    .addr {
      color: #ccc;
      width: 65px;
    }

    .hex {
      margin-left: 8px;

      .hex-cell {
        margin: 0px 1px;
        height: 22px;
        width: 20px;
      }

      :nth-child(9) {
        margin-left: 10px;
      }

      .selected {
        background: #fffb05;
      }
    }

    .ascii {
      margin-left: 12px;

      .ascii-cell {
        height: 22px;
        width: 8px;
      }
      .selected {
        background: #fffb05;
      }
    }
  }
}
.scroller-container {
  height: 500px !important;
  width: 100%;
  display: block;
  background-color: aquamarine
}
.scroller {  
  height: 300px;
  background-color: #f5adad;
  overflow-y: auto; /* 允许垂直滚动 */  
} 
</style>